package uk.ac.lkl.common.util.ds;



import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import uk.ac.lkl.common.util.ds.event.ListEvent;
import uk.ac.lkl.common.util.ds.event.ListListener;


/**
 * Wraps up a list so that can see additions/removals.
 * 
 * @author Darren Pearce
 * @version $Revision: 391 $
 * @version $Date: 2007-12-07 03:14:19 +0000 (Fri, 07 Dec 2007) $
 * 
 */
public abstract class AbstractNotifyingList<E> extends ArrayList<E> {

    private static final long serialVersionUID = 1L;


    private ArrayList<ListListener<E>> listeners;


    private Class<E> elementClass;


    public AbstractNotifyingList(Class<E> elementClass) {
        this(elementClass, new ArrayList<E>());
    }


    // use ArrayList so can remove. Hack.
    public AbstractNotifyingList(Class<E> elementClass, E [] elements) {
        this(elementClass, new ArrayList<E>(Arrays.asList(elements)));
    }


    public AbstractNotifyingList(Class<E> elementClass, Collection<E> collection) {
        super(collection);
        this.elementClass = elementClass;
        listeners = new ArrayList<ListListener<E>>();
    }


    public Class<E> getElementClass() {
        return elementClass;
    }


    // public abstract boolean add(E element);

    // public abstract void add(int index, E element);

    // of these 5, is only one that is not in ArrayList.
    public abstract boolean removeElement(E element);


    // public abstract E remove(int index);

    // public abstract boolean remove(Object element);

    protected void fireElementAdded(E element, int index) {
    	if (element instanceof Listable) ((Listable)element).addToList(this);
        ListEvent<E> e = ListEvent
                .createElementAddedEvent(this, element, index);
        for (ListListener<E> listener : listeners)
            listener.elementAdded(e);
    }


    protected void fireElementRemoved(E element, int index) {
    	if (element instanceof Listable) ((Listable)element).removeFromList(this);
        ListEvent<E> e = ListEvent.createElementRemovedEvent(
                                                             this,
                                                             element,
                                                             index);
        for (ListListener<E> listener : listeners)
            listener.elementRemoved(e);
    }


    protected void fireElementMoved(E element, int oldIndex, int newIndex) {
        ListEvent<E> e = ListEvent.createElementMovedEvent(
                                                           this,
                                                           element,
                                                           oldIndex,
                                                           newIndex);
        for (ListListener<E> listener : listeners)
            listener.elementMoved(e);
    }


    public void addListListener(ListListener<E> listener) {
        listeners.add(listener);
    }


    public void removeListListener(ListListener<E> listener) {
        listeners.remove(listener);
    }
}
